package com.mirror.flutter_huawei_cloud;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;

import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.model.ProgressListener;
import com.obs.services.model.ProgressStatus;
import com.obs.services.model.PutObjectRequest;
import com.obs.services.model.PutObjectResult;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.StreamHandler;

/**
 * FlutterHuaweiCloudPlugin
 */
public class FlutterHuaweiCloudPlugin implements FlutterPlugin, MethodCallHandler, StreamHandler {
    /// The MethodChannel that will the communication between Flutter and native
    /// Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine
    /// and unregister it
    /// when the Flutter Engine is detached from the Activity
    private static final String EVENT_CHANNEL_NAME = "flutter_huawei_cloud_progress";

    private static final ExecutorService executor = Executors.newSingleThreadExecutor();

    private EventChannel eventChannel;

    private EventChannel.EventSink eventSink;

    private MethodChannel channel;

    private ObsClient obsClient;

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_huawei_cloud");
        channel.setMethodCallHandler(this);

        eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), EVENT_CHANNEL_NAME);
        eventChannel.setStreamHandler(this);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        if (call.method.equals("initialize")) {
            initialize(call, result);
        } else if (call.method.equals("uploadFile")) {
            uploadFile(call, result);
        } else if (call.method.equals("uploadMultipleFile")) {
            uploadMultipleFile(call, result);
        } else if (call.method.equals("getPlatformVersion")) {
            result.success("Android " + android.os.Build.VERSION.RELEASE);
        } else {
            result.notImplemented();
        }
    }

    private void initialize(MethodCall call, Result result) {
        try {
            String accessKey = call.argument("accessKey");
            if (accessKey == null || accessKey.isEmpty()) {
                result.error("InvalidArgument", "accessKey不可为空", null);
                return;
            }
            String secretKey = call.argument("secretKey");
            if (secretKey == null || secretKey.isEmpty()) {
                result.error("InvalidArgument", "secretKey不可为空", null);
                return;
            }
            String region = call.argument("region");
            if (region == null || region.isEmpty()) {
                result.error("InvalidArgument", "region不可为空", null);
                return;
            }

            ObsConfiguration config = new ObsConfiguration();
            config.setEndPoint("obs." + region + ".myhuaweicloud.com");

            this.obsClient = new ObsClient(accessKey, secretKey, config);
            result.success(null);
        } catch (Exception e) {
            result.error("Initialize Error", e.getMessage(), null);
        }
    }

    private void uploadFile(MethodCall call, Result result) {
        try {
            // 参数验证（主线程安全）
            String bucketName = call.argument("bucketName");
            if (bucketName == null || bucketName.isEmpty()) {
                result.error("InvalidArgument", "bucketName不可为空", null);
                return;
            }
            String objectKey = call.argument("objectKey");
            if (objectKey == null || objectKey.isEmpty()) {
                result.error("InvalidArgument", "objectKey不可为空", null);
                return;
            }
            String filePath = call.argument("filePath");
            if (filePath == null || filePath.isEmpty()) {
                result.error("InvalidArgument", "filePath不可为空", null);
                return;
            }
            File uploadFile = new File(filePath);
            if (!uploadFile.exists()) {
//                throw new FileNotFoundException("File not found: " + filePath);
                result.error("InvalidArgument", "文件不存在", null);
                return;
            }

            executor.execute(() -> {
                try {
                    PutObjectRequest request = new PutObjectRequest(
                            bucketName,
                            objectKey,
                            uploadFile);

                    // 1. 进度监听器（使用弱引用）
                    request.setProgressListener(new ProgressListener() {

                        @Override
                        public void progressChanged(ProgressStatus status) {
                            Map<String, Object> progress = new HashMap<>();
                            progress.put("objectKey", objectKey);
                            progress.put("bytesSent", status.getTransferredBytes());
                            progress.put("totalBytes", status.getTotalBytes());

                            new Handler(Looper.getMainLooper()).post(() -> {
                                if (eventSink != null) {
                                    eventSink.success(progress);
                                }
                            });
                        }
                    });

                    // 2. 设置合理的回调间隔（可配置）
                    request.setProgressInterval(1024 * 200); // 1MB触发一次

                    // 3. 执行上传
                    PutObjectResult putObjectResult = obsClient.putObject(request);

                    // 4. 切换到主线程处理结果
                    new Handler(Looper.getMainLooper()).post(() -> {
                        if (putObjectResult.getStatusCode() == 200) {
                            String remoteUrl = putObjectResult.getObjectUrl()
                                    .replaceAll("%2F", "/");
                            result.success(remoteUrl);
                        } else {
                            result.error("Upload Failed",
                                    putObjectResult.getResponseHeaders().toString(), null);
                        }
                    });

                } catch (Exception e) {
                    // 5. 异常处理切换到主线程
                    new Handler(Looper.getMainLooper()).post(() -> {
                        if (result != null) {
                            result.error("Upload Failed",
                                    e.getClass().getSimpleName() + ": " + e.getMessage(),
                                    null);
                        }
                    });
                }
            });

        } catch (Exception e) {
            // 主线程异常直接处理
            result.error("Upload Failed",
                    e.getClass().getSimpleName() + ": " + e.getMessage(),
                    null);
        }
    }

    private void uploadFile1(MethodCall call, Result result) {
        try {
            String bucketName = call.argument("bucketName");
            if (bucketName == null || bucketName.isEmpty()) {
                result.error("InvalidArgument", "bucketName不可为空", null);
                return;
            }
            String objectKey = call.argument("objectKey");
            if (objectKey == null || objectKey.isEmpty()) {
                result.error("InvalidArgument", "objectKey不可为空", null);
                return;
            }
            String filePath = call.argument("filePath");
            if (filePath == null || filePath.isEmpty()) {
                result.error("InvalidArgument", "filePath不可为空", null);
                return;
            }

            executor.execute(() -> {
                try {
                    PutObjectRequest request = new PutObjectRequest(
                            bucketName,
                            objectKey,
                            new File(filePath));
                    request.setProgressListener(new ProgressListener() {
                        @Override
                        public void progressChanged(ProgressStatus status) {
                            Log.i("PutObject", "AverageSpeed:" + status.getAverageSpeed());
                            Log.i("PutObject", "TransferPercentage:" + status.getTransferPercentage());
                            Map<String, Object> progress = new HashMap<>();
                            progress.put("objectKey", objectKey);
                            progress.put("bytesSent", status.getTransferredBytes());
                            progress.put("totalBytes", status.getTotalBytes());
                            new Handler(Looper.getMainLooper()).post(() -> {
                                if (eventSink != null) {
                                    eventSink.success(progress);
                                }
                            });
                        }
                    });
                    request.setProgressInterval(1024 * 200);

                    PutObjectResult putObjectResult = obsClient.putObject(request);
                    int code = putObjectResult.getStatusCode();
                    String remoteUrl = putObjectResult.getObjectUrl().replaceAll("%2F", "/");
                    if (code == 200) {
                        result.success(remoteUrl);
                    } else {
                        result.error("Upload Failed", putObjectResult.getResponseHeaders().toString(), null);
                    }
                } catch (Exception e) {
                    result.error("Upload Failed", e.getMessage(), null);
                }
            });
            // executor.shutdown();
        } catch (Exception e) {
            result.error("Upload Failed", e.getMessage(), null);
        }
    }

    private void uploadMultipleFile(MethodCall call, Result result) {
        try {
            String bucketName = call.argument("bucketName");
            if (bucketName == null || bucketName.isEmpty()) {
                result.error("InvalidArgument", "bucketName不可为空", null);
                return;
            }
            List<Map<String, String>> files = call.argument("files");
            if (files == null || files.isEmpty()) {
                result.error("InvalidArgument", "files不可为空", null);
                return;
            }

            // 原子标记确保只报告一次错误
            AtomicBoolean hasReportedError = new AtomicBoolean(false);
            CountDownLatch latch = new CountDownLatch(files.size());
            Map<String, String> resultMap = new ConcurrentHashMap<>();

            for (Map<String, String> m : files) {
                String objectKey = m.get("objectKey");
                String filePath = m.get("filePath");
                if (filePath == null) continue;

                executor.execute(() -> {
                    // 检查是否已有错误发生，避免继续执行
                    if (hasReportedError.get()) {
                        latch.countDown();
                        return;
                    }

                    try {
                        PutObjectRequest request = new PutObjectRequest(
                                bucketName, objectKey, new File(filePath));

                        PutObjectResult putObjectResult = obsClient.putObject(request);
                        int code = putObjectResult.getStatusCode();
                        String remoteUrl = putObjectResult.getObjectUrl().replace("%2F", "/");

                        if (code == 200) {
                            resultMap.put(objectKey, remoteUrl);
                        } else {
                            throw new Exception("Upload failed with status: " + code);
                        }
                    } catch (Exception e) {
                        // 仅第一个错误触发全局响应
                        if (hasReportedError.compareAndSet(false, true)) {
                            new Handler(Looper.getMainLooper()).post(() -> {
                                result.error("Upload Failed", e.getMessage(), null);
                            });
                        }
                    } finally {
                        latch.countDown();

                        int remainCount = (int) latch.getCount();
                        new Handler(Looper.getMainLooper()).post(() -> {
                            Map<String, Object> progress = new HashMap<>();
                            progress.put("objectKey", objectKey);
                            progress.put("bytesSent", files.size() - remainCount);
                            progress.put("totalBytes", files.size());
                            if (eventSink != null) {
                                eventSink.success(progress);
                            }
                        });
                    }
                });
            }

            // 单独线程等待所有任务完成
            executor.execute(() -> {
                try {
                    latch.await();
                    // 所有任务完成后，检查是否未报告过错误
                    if (!hasReportedError.get()) {
                        new Handler(Looper.getMainLooper()).post(() -> {
                            result.success(resultMap);
                        });
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });

        } catch (Exception e) {
            result.error("Upload Failed", e.getMessage(), null);
        }
    }

//    private void uploadMultipleFile(MethodCall call, Result result) {
//        try {
//            String bucketName = call.argument("bucketName");
//            if (bucketName == null || bucketName.isEmpty()) {
//                result.error("InvalidArgument", "bucketName不可为空", null);
//                return;
//            }
//            List<Map<String, String>> files = call.argument("files");
//            if (files == null) {
//                result.error("InvalidArgument", "files不可为空", null);
//                return;
//            }
//
//            CountDownLatch latch = new CountDownLatch(files.size());
//            Map<String, String> resultMap = new ConcurrentHashMap<>();
//
//            for (Map<String, String> m : files) {
//                String objectKey = m.get("objectKey");
//                String filePath = m.get("filePath");
//                assert filePath != null;
//                executor.execute(() -> {
//                    try {
//                        PutObjectRequest request = new PutObjectRequest(
//                                bucketName,
//                                objectKey,
//                                new File(filePath));
//
//                        PutObjectResult putObjectResult = obsClient.putObject(request);
//                        int code = putObjectResult.getStatusCode();
//                        String remoteUrl = putObjectResult.getObjectUrl().replaceAll("%2F", "/");
//                        // Log.w("UploadResult", remoteUrl, null);
//                        if (code == 200) {
//                            resultMap.put(objectKey, remoteUrl);
//                        } else {
//                            resultMap.put(objectKey, "");
//                        }
//                    } catch (Exception e) {
//                        resultMap.put(objectKey, "");
//                    } finally {
//                        latch.countDown();
//
//                        int remainCount = (int) latch.getCount();
//                        new Handler(Looper.getMainLooper()).post(() -> {
//                            Map<String, Object> progress = new HashMap<>();
//                            progress.put("objectKey", objectKey);
//                            progress.put("bytesSent", files.size() - remainCount);
//                            progress.put("totalBytes", files.size());
//                            if (eventSink != null) {
//                                eventSink.success(progress);
//                            }
//                        });
//                    }
//                });
//            }
//
//            executor.execute(() -> {
//                try {
//                    latch.await();
//                    new Handler(Looper.getMainLooper()).post(() -> {
//                        result.success(resultMap);
//                        // LinkedHashMap<String, String> orderedResult = new LinkedHashMap<>();
//                        // for (String name : files) {
//                        // orderedResult.put(name, resultMap.get(name));
//                        // }
//                        // result.success(orderedResult);
//                    });
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                }
//            });
//
//        } catch (Exception e) {
//            result.error("Upload Failed", e.getMessage(), null);
//        }
//    }

    @Override
    public void onListen(Object arguments, EventChannel.EventSink events) {
        Log.i("FlutterHuaweiCloud", "onListen", null);
        this.eventSink = events;
    }

    @Override
    public void onCancel(Object arguments) {
        Log.i("FlutterHuaweiCloud", "onCancel", null);
        this.eventSink.endOfStream();
        this.eventSink = null;
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        channel.setMethodCallHandler(null);
        eventChannel.setStreamHandler(null);
        executor.shutdown();
    }
}
